/**
 * 
 */
package de.fsujena.chat_pi.connection;

import java.io.*;
import java.security.*;

import javax.crypto.*;

/**
 * @author Erik Hebestreit
 * @author David Reifert
 */
public class RSAencryption {
	private Key serverPublicKey;
	private Key serverPrivateKey;
	private Key clientPublicKey;

	protected CipherInputStream cis;
	protected CipherOutputStream cos;

	/**
	 * @throws RSAException 
	 * 
	 */
	public RSAencryption() throws RSAException {
		this.createKeyPair();
	}

	/**
	 * creates public and private key for encryption
	 * @throws RSAException
	 */
	private void createKeyPair() throws RSAException {
		try {
			KeyPairGenerator kpg;
			kpg = KeyPairGenerator.getInstance("RSA");
			kpg.initialize(2048, new SecureRandom());

			KeyPair kp = kpg.genKeyPair();
			this.serverPublicKey = kp.getPublic();
			this.serverPrivateKey = kp.getPrivate();
		} catch (NoSuchAlgorithmException e) {
			throw new RSAException("algorithm error");
		}
	}

	/**
	 * sends the public key to server/client
	 * @param oos	reference to the objectoutputstream that sends the key
	 * @throws IOException
	 */
	public void sendPublicKey(ObjectOutputStream oos) throws IOException {
		oos.writeObject(serverPublicKey);
		oos.flush();
	}

	/**
	 * receives the public key from client/server
	 * @param ois		objectinputstream that receives the key
	 * @throws IOException
	 * @throws RSAException
	 */
	public void receivePublicKey(ObjectInputStream ois) throws IOException, RSAException {
		try {
			Object inputObject = ois.readObject();			//read key
			if (inputObject instanceof Key) {
				this.clientPublicKey = (Key) inputObject;	//cast input into key and saves it
				return;
			} else {
				System.out.println("is no key");
				return;
			}
		} catch (ClassNotFoundException e) {
			throw new RSAException("key delivery error");
		}
	}

	/**
	 * initializing the encrypted streams
	 * @param in	the inputstream
	 * @param out	the outputstream
	 * @throws RSAException
	 */
	protected void initializeCipherStreams(InputStream in, OutputStream out) throws RSAException {
		try {
			Cipher cipherIn = Cipher.getInstance("RSA");
			cipherIn.init(Cipher.DECRYPT_MODE, serverPrivateKey);

			Cipher cipherOut = Cipher.getInstance("RSA");
			cipherOut.init(Cipher.ENCRYPT_MODE, clientPublicKey);

			cis = new CipherInputStream(in, cipherIn);
			cos = new CipherOutputStream(out, cipherOut);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			throw new RSAException("algorithm error");
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
			throw new RSAException("padding error");
		} catch (InvalidKeyException e) {
			e.printStackTrace();
			throw new RSAException("invalid keys");
		}
	}
}